"""
-*- coding: utf-8 -*-
@Author  : Link
@Time    : 2022/5/12 13:53
@Software: PyCharm
@File    : trans_bar.py
@Remark  : 
"""

import math

import numpy as np
import pandas as pd
from PySide2 import QtWidgets, QtCore
from pyqtgraph import InfiniteLine

from chart_core.chart_pyqtgraph.utils import CustomViewBox, PlotWidget, BarGraphItem, graph_range_signal, Mixin

# class BarGraph(BarGraphItem):
#     def mouseClickEvent(self, event):
#         print("clicked")
from workspace_core.core_to_analysis_stdf.stdf_variable import GlobalVariable


class TransBarChart(QtCore.QObject, Mixin):
    """
    横向柱状图
    初始化就需要有两个bar_item, 一个放front_df, 另一个放chart_df
    """
    key = None
    li = None

    bar_width = 0  # 这个是柱状图的当前宽度
    bins_num = 60

    ticks = None  # type:list
    select_start = 0
    select_stop = 0

    front_data_min = 0
    front_data_max = 0

    list_bins = None

    lines = None
    unit = ''
    change = False

    def __init__(self):
        super(TransBarChart, self).__init__()
        self.vb = CustomViewBox()
        self.pw = PlotWidget(viewBox=self.vb, enableMenu=False)
        self.pw.hideButtons()
        self.bg1 = BarGraphItem(x0=[], y=[], y0=[], y1=[], width=[])
        self.bg2 = BarGraphItem(x0=[], y=[], y0=[], y1=[], width=[])
        self.pw.addItem(self.bg1)
        self.pw.addItem(self.bg2)
        self.bottom_axis = self.pw.getAxis("bottom")
        self.bottom_axis.setHeight(60)
        self.left_axis = self.pw.getAxis("left")
        self.left_axis.setWidth(60)
        self.pw.setMouseEnabled(x=False)
        self.vb.select_signal.connect(self.select_range)
        self.rota = 0b0101

    def init_movable_line(self):
        h_line = InfiniteLine(angle=0, movable=False, label='y={value:0.5f}', labelOpts={'color': (0, 0, 0)})
        self.vb.addItem(h_line, ignoreBounds=True)

        def mouseMoved(evt):
            if self.vb.sceneBoundingRect().contains(evt):
                mouse_point = self.vb.mapSceneToView(evt)
                h_line.setPos(mouse_point.y())

        self.vb.scene().sigMouseMoved.connect(mouseMoved)

    def set_data(self, key: str):
        if self.li is None:
            raise Exception("first set li")
        self.key = key
        self.set_title(key)
        self.front_data_min = self.li.front_df[self.key].min()
        self.front_data_max = self.li.front_df[self.key].max()

    def set_front_df_chart(self):
        if self.key not in self.li.front_df:
            return
        temp_df = self.li.front_df[
            (self.li.front_df[self.key] > self.front_data_min) & (self.li.front_df[self.key] < self.front_data_max)]
        if len(temp_df) == 0:
            return
        self.list_bins = np.linspace(self.front_data_min, self.front_data_max, self.bins_num)
        columns, x0, y0, y1, y, width, self.bar_width = [], [], [], [], [], [], 0

        for c, (key, e_df) in enumerate(temp_df.groupby(["GROUP", "DA_GROUP"])):
            key = f"{key[0]}@{key[1]}"
            if self.ticks is not None and key not in self.ticks:
                self.change = False
            temp_dis = e_df[self.key].value_counts(bins=self.list_bins, sort=False)
            self.bar_width = max(temp_dis) if max(temp_dis) > self.bar_width else self.bar_width
            if not self.change:
                columns.append(key)
            else:
                if len(e_df) == 0:
                    continue
                c = self.ticks.index(key)
            for bin_index, value in enumerate(temp_dis.values):
                x0.append(c + 0.2)
                y0.append(self.list_bins[bin_index])
                y1.append(self.list_bins[bin_index + 1])
                y.append((self.list_bins[bin_index + 1] + self.list_bins[bin_index]) / 2)
                width.append(value)
        x0 = np.array(x0) * self.bar_width
        self.bg1.setOpts(x0=x0, y=y, y0=y0, y1=y1, width=width, brush=(217, 83, 25, 140))
        if not self.change:
            self.ticks = columns
        ticks = [((idx + 0.2) * self.bar_width, label.replace("|", "\r\n").replace("@", "\r\n"))
                 for idx, label in enumerate(self.ticks)]
        self.bottom_axis.setTicks((ticks, []))
        # self.vb.setYRange(self.front_data_min, self.front_data_max)
        self.change = True

    def select_range(self, ax: QtCore.QRectF):
        """
        区间选取后触发,更新chart_df
        :return:
        """
        if ax is None:
            """
            show all front
            """
            self.li.refresh_chart()
            return
        self.select_start = math.ceil(ax.left() / self.bar_width)
        self.select_stop = math.ceil(ax.right() / self.bar_width)
        if self.select_start > len(self.ticks) or self.select_stop < 0:
            return
        g_key, d_key = [], []
        for i in range(self.select_start - 1, self.select_stop):
            if i < 0:
                continue
            if i == len(self.ticks):
                break
            g, d = self.ticks[i].split("@")
            g_key.append(g)
            d_key.append(d)
        self.li.set_new_chart_df(
            self.li.front_df[(self.li.front_df["GROUP"].isin(g_key)) & (self.li.front_df["DA_GROUP"].isin(d_key)) &
                             (self.li.front_df[self.key] > ax.top()) & (self.li.front_df[self.key] < ax.bottom())]
        )

    def set_chart_df_chart(self):
        if self.key not in self.li.chart_df:
            return
        if len(self.li.chart_df) == 0:
            self.bg2.setOpts(x0=[], y=[], y0=[], y1=[], width=[])
            return
        if self.list_bins is None:
            return
        x0, y0, y1, y, width = [], [], [], [], []
        for key, e_df in self.li.chart_df.groupby(["GROUP", "DA_GROUP"]):
            key = f"{key[0]}@{key[1]}"
            if len(e_df) == 0:
                continue
            i = self.ticks.index(key)
            temp_dis = e_df[self.key].value_counts(bins=self.list_bins, sort=False)
            for bin_index, value in enumerate(temp_dis.values):
                x0.append(i + 0.2)
                y0.append(self.list_bins[bin_index])
                y1.append(self.list_bins[bin_index + 1])
                y.append((self.list_bins[bin_index + 1] + self.list_bins[bin_index]) / 2)
                width.append(value)
        x0 = np.array(x0) * self.bar_width
        self.bg2.setOpts(x0=x0, y=y, y0=y0, y1=y1, width=width, brush=(217, 83, 25, 255))

    @graph_range_signal
    def set_range_data_to_chart(self, a, ax):
        if self.li is None:
            return
        if not self.change:
            return
        percent = (ax[1][1] - ax[1][0]) / (self.front_data_max - self.front_data_min)
        if 0.85 < percent < 1.15:
            """ 性能会好些,体验会差点 """
            return
        self.front_data_min, self.front_data_max = ax[1]
        self.set_front_df_chart()
        self.set_chart_df_chart()

    def full_change_chart(self):
        self.set_front_df_chart()
        self.set_chart_df_chart()
